# -*- coding: utf-8 -*-
from datetime import date, datetime
from random import random
from threading import Lock
from time import sleep
from functools import partial
from concurrent.futures import Executor, Future
from concurrent.futures.thread import ThreadPoolExecutor
from concurrent.futures.process import ProcessPoolExecutor

import py_global
import logging

logger = logging.getLogger(__name__)


class Object(object):

    def __init__(self):
        self.obj_attr = 'instance_attribute'

    def __str__(self):
        return f'obj_attr:{self.obj_attr}.'


def test_func_param_type(no: int, name: str, task_date: date, obj: Object, *args, **kwargs):
    """
    测试函数参数类型：支持不同类型的参数
    :param no:
    :param name:
    :param task_date:
    :param obj:
    :param args:
    :param kwargs:
    :return:
    """
    logger.info(f'parameters:{no},{name},{task_date},{obj},{args},{kwargs}.')
    sleep(1)
    return len(args), len(kwargs)


def sleep_random_seconds():
    """
    睡眠随机时间
    :return:
    """
    seconds = random() * 60
    logger.info(f'sleep({seconds}) start')
    sleep(seconds)
    logger.info(f'sleep({seconds}) stop')
    return seconds


def sleep_custom_seconds(seconds: int):
    """
    睡眠指定时间
    :param seconds:
    :return:
    """
    logger.info(f'sleep({seconds}) start')
    sleep(seconds)
    logger.info(f'sleep({seconds}) stop')
    return seconds


def nest_thread_pool(size: int):
    """
    嵌套线程池
    :param size:
    :return:
    """
    with ThreadPoolExecutor(max_workers=4) as executor:  # 线程池
        future_list = [executor.submit(sleep_random_seconds) for i in range(size)]
        pass
    result_list = [future.result() for future in future_list]
    logger.info(result_list)
    return result_list


def test_thread_pool():
    """测试线程池"""
    kwargs = dict()
    obj = Object()
    args = (1, 'cch', datetime.now().date(), obj)
    test_func_param_type(*args, **kwargs)
    with ThreadPoolExecutor(max_workers=4) as executor:  # 线程池
        future_list = [executor.submit(test_func_param_type, *args, **kwargs) for i in range(5)]
        # future_list = [executor.submit(service, i, str(i)) for i in range(1, 5)]
        # future_list = [executor.submit(nest_thread_pool, i) for i in range(1, 5)]
        pass

    result_list = [future.result() for future in future_list]
    logger.info(f'result_list:{result_list}')

    pass


def test_process_pool():
    """测试进程池"""
    kwargs = dict()
    obj = Object()
    args = (1, 'cch', datetime.now().date(), obj)
    test_func_param_type(*args, **kwargs)
    with ProcessPoolExecutor(max_workers=4) as executor:  # 进程池
        future_list = [executor.submit(test_func_param_type, *args, **kwargs) for i in range(5)]
        # future_list = [executor.submit(service, i, str(i)) for i in range(1, 5)]
        pass

    result_list = [future.result() for future in future_list]
    logger.info(f'result_list:{result_list}')
    pass


def test_future():
    executor: Executor = ThreadPoolExecutor(max_workers=4)
    args = (10,)
    args = tuple()
    kwargs = dict()
    future: Future = executor.submit(sleep_custom_seconds, *args, **kwargs)
    params = {
        'args': args,
        'kwargs': kwargs,
    }
    callback_func = partial(done_callback, params)
    future.add_done_callback(callback_func)
    executor.shutdown()


def done_callback(params, future):
    logger.info(f'task done;params:{params}')
    e = future.exception()
    if e:
        logger.exception(f'run task error:{repr(e)}')


if __name__ == '__main__':
    # test_thread_pool()
    # test_process_pool()
    # nest_thread_pool(4)
    test_future()

    pass
